#include "Bussiness.h"

#define MAXLINE 1024
#define BIG_FILE_SIZE (100 * 1024 * 1024)
#define MMAP_SIZE (1024 * 1024)

int recvn(int fd, void* buf, int length) {
    int bytes = 0; 
    while (bytes < length) {
        int n = recv(fd, (char*)buf + bytes, length - bytes, 0);
        if (n < 0) {
            return -1;
        }
        bytes += n;
    } // bytes == length
    return 0;
}

int sendn(int fd, void* buf, int length) {
    int bytes = 0;
    while (bytes < length) {
        int n = send(fd, (char*)buf + bytes, length - bytes, MSG_NOSIGNAL);
        if (n < 0) {
            return -1;
        }
        bytes += n;
    } // bytes == length 
    return 0;
}

typedef struct {
    int length;
    char data[MAXLINE];
} DataBlock;

/* void send_file(int sockfd) */
/* { */
/*     int fd = open("file1", O_RDONLY); */
/*     if (fd == -1) { */
/*         error(0, errno, "open %s failed", "file1"); */
/*     } */
/*     // 先把文件的名字发送过去 */
/*     DataBlock block = {5, "file1"}; */
/*     sendn(sockfd, &block, sizeof(int) + block.length); */
/*     // 发送文件的大小 */
/*     struct stat statbuf; */
/*     fstat(fd, &statbuf); */
/*     off_t fsize = statbuf.st_size; */
/*     sendn(sockfd, &fsize, sizeof(fsize)); */
/*     // 再发送文件的内容 */
/*     int n; */
/*     while ((n = read(fd, block.data, MAXLINE)) > 0) { */
/*         block.length = n; */
/*         sendn(sockfd, &block, sizeof(int) + block.length); */
/*     } */
/*     // 最后发送长度为 0 的数据块 */
/*     block.length = 0; */
/*     sendn(sockfd, &block, sizeof(int)); */
/* } */

/* void recv_file(int sockfd) { */
/*     // 先接收文件的名字 */
/*     DataBlock block; */
/*     bzero(&block, sizeof(block)); */
/*     recvn(sockfd, &block.length, sizeof(int)); */
/*     recvn(sockfd, block.data, block.length); */
/*     // 打开文件 */
/*     int fd = open(block.data, O_WRONLY | O_TRUNC | O_CREAT, 0666); */
/*     if (fd == -1) { */
/*         error(0, errno, "open %s failed", block.data); */
/*     } */
/*     // 接收文件的大小 */
/*     off_t fsize; */
/*     recvn(sockfd, &fsize, sizeof(fsize)); */
/*     off_t bytes = 0; */
/*     // 再接收文件的内容 */
/*     while (1) { */
/*         recvn(sockfd, &block.length, sizeof(int)); */
/*         if (block.length == 0) { */
/*             break; */
/*         } */
/* #ifdef DEBUG */ 
/*         if (block.length != MAXLINE) { */
/*             printf("block.length = %d\n", block.length); */
/*         } */
/* #endif */
/*         recvn(sockfd, block.data, block.length); */
/*         write(fd, block.data, block.length); */
/*         // 打印进度条 */
/*         bytes += block.length; */
/*         printf("%5.2lf%%\r", 100.0 * bytes / fsize); */
/*         fflush(stdout); */
/*     } */
/* } */

void send_file(int sockfd)
{
    int fd = open("file1", O_RDONLY);
    if (fd == -1) {
        error(0, errno, "open %s failed", "file1");
    }
    // 先把文件的名字发送过去
    DataBlock block = {5, "file1"};
    sendn(sockfd, &block, sizeof(int) + block.length);
    // 发送文件的大小
    struct stat statbuf;
    fstat(fd, &statbuf);
    off_t fsize = statbuf.st_size;
    sendn(sockfd, &fsize, sizeof(fsize));

    // 再发送文件的内容
    off_t bytes = 0; // 已发送的字节数目
    if (fsize >= BIG_FILE_SIZE) {
        // 大文件
        while (bytes < fsize) {
            off_t length;
            if (fsize - bytes >= MMAP_SIZE) {
                length = MMAP_SIZE;
            } else {
                length = fsize - bytes;
            }
            // 内存映射
            void* addr = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, bytes);
            sendn(sockfd, addr, length);
            munmap(addr, length);
            bytes += length;
        }
    } else {
        // 小文件
        char buf[MAXLINE];
        while (bytes < fsize) {
            int length;
            if (fsize - bytes >= MAXLINE) {
                length = MAXLINE;
            } else {
                length = fsize - bytes;
            }
            read(fd, buf, length);
            sendn(sockfd, buf, length);
            bytes += length;
        }
    }
}

void recv_file(int sockfd) {
    // 先接收文件的名字
    DataBlock block;
    bzero(&block, sizeof(block));
    recvn(sockfd, &block.length, sizeof(int));
    recvn(sockfd, block.data, block.length);
    // 打开文件
    int fd = open(block.data, O_RDWR | O_TRUNC | O_CREAT, 0666);
    if (fd == -1) {
        error(0, errno, "open %s failed", block.data);
    }
    // 接收文件的大小
    off_t fsize;
    recvn(sockfd, &fsize, sizeof(fsize));
    off_t bytes = 0;
    // 再接收文件的内容
    if (fsize >= BIG_FILE_SIZE) {
        ftruncate(fd, fsize); 
        // 大文件
        while (bytes < fsize) {
            off_t length;
            if (fsize - bytes >= MMAP_SIZE) {
                length = MMAP_SIZE;
            } else {
                length = fsize - bytes;
            }
            // 内存映射
            void* addr = mmap(NULL, length, PROT_READ | PROT_WRITE, 
                              MAP_SHARED, fd, bytes);
            recvn(sockfd, addr, length);
            munmap(addr, length);
            bytes += length;
            // 打印进度条
            printf("%5.2lf%%\r", 100.0 * bytes / fsize);
            fflush(stdout);
        }
    } else {
        // 小文件
        char buf[MAXLINE];
        while (bytes < fsize) {
            int length;
            if (fsize - bytes >= MAXLINE) {
                length = MAXLINE;
            } else {
                length = fsize - bytes;
            }
            recvn(sockfd, buf, length);
            write(fd, buf, length);
            bytes += length;
            // 打印进度条
            printf("%5.2lf%%\r", 100.0 * bytes / fsize);
            fflush(stdout);
        }
    }
}


